package net.homelinux.chaoswg.io.renga.krypto.operations.type;

import java.math.BigInteger;

import net.homelinux.chaoswg.io.higherorderfunctions.AbstractQuadtaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.QuadtaryFunction;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.UnsignedNBit;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.UnsignedNBitFactory;

public class Merge4 extends AbstractQuadtaryFunction<UnsignedNBit, UnsignedNBit, UnsignedNBit, UnsignedNBit, UnsignedNBit> implements QuadtaryFunction<UnsignedNBit, UnsignedNBit, UnsignedNBit, UnsignedNBit, UnsignedNBit> {
    private boolean allOfSameType (final UnsignedNBit... unbs) {
        final Class tmp = unbs[0].getClass();
        
        for (final UnsignedNBit unb : unbs) {
            if (! unb.getClass().equals(tmp)) {
                return false;
            }
        }
        return true;
    }

    public final UnsignedNBit apply(final UnsignedNBit unb0, final UnsignedNBit unb1, final  UnsignedNBit unb2, final UnsignedNBit unb3) {
        final UnsignedNBitFactory unbFactory = UnsignedNBitFactory.createUnsignedNBitFactory(); 
        final int toMergeFrom = 4;

        if (allOfSameType(unb0, unb1, unb2, unb3) && unbFactory.exists(unb0.getN() * toMergeFrom)) {
            BigInteger tmp = new BigInteger("0");

            BigInteger[] u = { unb0.getValue(), unb1.getValue(), unb2.getValue(), unb3.getValue()}; 

            for (int i = 0; i < toMergeFrom; ++i) {
                tmp = tmp.shiftLeft(unb0.getN());
                tmp = tmp.or(u[i]);
            }


            final UnsignedNBit toReturn = unbFactory.get(toMergeFrom*unb0.getN());
            toReturn.setValue(tmp);

            return toReturn;

        }
        return null;
    }
    
    public String toString () {
        return "Merge from four";
    }
}
